import React, { useEffect, useState } from 'react'
import { Toast } from 'antd-mobile'
import { getMapDataAPI, getHousesListAPI } from '../../api'
import { serverurl } from '../../utils/request'
import './index.scss'
import NavHeader from '../../components/NavHeader'
import styles from './index.module.css'
import { Link, useNavigate } from 'react-router-dom'

// 注意：在react脚手架中全局对象需要使用window来访问，否则会造成EsLint校验错误
const BMapGL = window.BMapGL // 定义一个全局变量

// 覆盖物样式
const labelStyle = {
  cursor: 'pointer',
  border: '0px solid rgb(255, 0, 0)',
  padding: '0px',
  whiteSpace: 'nowrap',
  fontSize: '12px',
  color: ' rgb(255, 255, 255)',
  textAlign: 'center',
}

function Map() {
  const navigate = useNavigate()
  // 小区房源数据
  const [houseList, setHouseList] = useState([])
  // 控制小区房源数据是否显示
  const [isHouseList, setIsHouseList] = useState(false)

  useEffect(() => {
    initMapHandler() // 调用初始化地图方法
  }, [])

  // 初始化地图
  const initMapHandler = () => {
    // 获取当前定位城市
    const { label, value } = JSON.parse(localStorage.getItem('hkzf_city'))
    // console.log(label, value)
    // 3.创建地图实例
    let map = new BMapGL.Map('container')
    // 挂载到React上
    React.map = map
    // console.log('react', React.map)
    // 创建地址解析器实例,解析当前城市坐标
    const myGeo = new BMapGL.Geocoder()
    // 将地址解析结果显示在地图上，并调整地图视野
    myGeo.getPoint(
      label,
      async function (point) {
        if (point) {
          // 放大地图，point就是当前城市的坐标，11是放大级别
          map.centerAndZoom(point, 11)
          // 添加所需控件
          map.addControl(new BMapGL.ScaleControl()) // 添加比例尺控件
          map.addControl(new BMapGL.ZoomControl()) // 添加缩放控件
          map.addControl(new BMapGL.CityListControl()) // 添加城市列表控件

          // 获取房源数据
          // const { data: res } = await getMapDataAPI(value)
          // console.log('res', res.body)

          // 调用 renderOverlays方法
          renderOverlays(value)

          // 遍历数据
          // res.body.forEach((item) => {
          //   // 解构出需要的数据
          //   const {
          //     coord: { latitude, longitude },
          //     label: areaLabel,
          //     value,
          //     count,
          //   } = item

          //   // 当前覆盖物的坐标
          //   const areaPoint = new BMapGL.Point(longitude, latitude)
          //   // 创建覆盖物
          //   const opts = {
          //     position: areaPoint, // 指定标注所在的地理位置
          //     offset: new BMapGL.Size(-35, -35), // 设置偏移量
          //   }
          //   // 创建Label实例对象,标注对象，设置 setContent 后，第一个参数中设置的文本内容就失效了，因此直接清空即可。
          //   const label = new BMapGL.Label('', opts)

          //   // 给每一个覆盖物添加唯一标识
          //   label.id = value

          //   // 设置房源覆盖物内容,这里使用的是原生dom，使用class，不使用className
          //   label.setContent(`
          //     <div class="${styles.bubble}">
          //       <p class="${styles.name}">${areaLabel}</p>
          //       <p>${count}套</p>
          //     </div>
          //   `)

          // // 调用 setStyle 方法设置样式
          // label.setStyle(labelStyle)

          //   // 给房源覆盖物添加单击事件
          //   label.addEventListener('click', () => {
          //     // 获取到唯一标识 label.id
          //     console.log('click了', label.id)
          //     // 放大地图，以当前点击的覆盖物为中心放大地图。第一个参数：当前坐标对象。第二个参数：放大级别
          //     map.centerAndZoom(areaPoint, 13)
          //     // 调用 clearOverlays() 方法清除当前覆盖物信息。
          //     map.clearOverlays()
          //   })

          //   // 在map对象上调用 addOverlay 方法，将覆盖物添加到地图中
          //   map.addOverlay(label)
          // })
        } else {
          Toast.show({
            icon: 'fail',
            content: '您选择的地址没有解析到结果！',
          })
        }
      },
      label
    )

    // 监听地图的 movestart 事件，在地图移动时隐藏房源列表
    map.addEventListener('movestart', () => {
      if (houseList) {
        setIsHouseList(false)
      }
    })
  }

  // renderOverlays ：渲染覆盖物入口
  // 1. 接收区域id做为参数，获取该区域下的房源数据
  // 2. 调用 getTypeAndZoom 获取房源类型以及下级地图缩放级别
  const renderOverlays = async (id) => {
    // 这里需要使用定时器包裹一下,防止点击的时候获取不到 下一级的缩放级别和类型
    setTimeout(async () => {
      // 调用 getTypeAndZoom 方法获取级别和类型
      const { nextZoom, type } = await getTypeAndZoom()
      console.log('下一级缩放级别, 类型', nextZoom, type)
      // 获取房源数据
      const { data: res } = await getMapDataAPI(id)
      const data = res.body
      data.forEach((item) => {
        // 创建覆盖物
        createOverlays(item, nextZoom, type)
      })
    }, 500)
  }

  // getTypeAndZoom：计算要绘制的覆盖物类型和下一个缩放级别
  // 区：11，范围：>=10 <12
  // 镇：13，范围：>=12 <14
  // 小区：15，范围：>=14 <16
  const getTypeAndZoom = () => {
    let nextZoom, type // 声明下一个缩放级别和类型
    const zoom = React.map.getZoom() // 调用地图的 getZoom 方法，来获取当前的缩放级别
    console.log('当前地图缩放级别: ', zoom)
    if (zoom >= 10 && zoom < 12) {
      // 区
      nextZoom = 13 // 下一个缩放级别
      type = 'circle' // circle 表示绘制圆形覆盖物（区、镇）
    } else if (zoom >= 12 && zoom < 14) {
      // 镇
      nextZoom = 15
      type = 'circle'
    } else if (zoom >= 14 && zoom < 16) {
      // 小区
      type = 'rect' // 矩形覆盖物（小区）
    }

    // 返回出去
    return {
      nextZoom,
      type,
    }
  }

  // createOverlays：根据传入的类型，调用对应的方法来创建覆盖物，并提供参数
  const createOverlays = (data, zoom, type) => {
    // 解构出需要的数据
    const {
      coord: { latitude, longitude },
      label: areaName,
      value,
      count,
    } = data

    // 创建当前覆盖物的坐标
    const areaPoint = new BMapGL.Point(longitude, latitude)
    // 判断类型调用不同的方法，并提供参数
    if (type === 'rect') {
      // 小区
      createRect(areaPoint, areaName, value, count)
    } else {
      // 区或镇
      createCircle(areaPoint, areaName, value, count, zoom)
    }
  }

  // createCircle：根据传入的数据创建区、镇的覆盖物，绑定事件（放大地图、清除覆盖物、渲染下一级房源数据）
  const createCircle = (areaPoint, areaName, value, count, zoom) => {
    // 创建覆盖物
    const opts = {
      position: areaPoint, // 指定标注所在的地理位置
      offset: new BMapGL.Size(-35, -35), // 设置偏移量
    }
    // 创建Label实例对象,标注对象，设置 setContent 后，第一个参数中设置的文本内容就失效了，因此直接清空即可。
    const label = new BMapGL.Label('', opts)

    // 给每一个覆盖物添加唯一标识
    label.id = value

    // 设置房源覆盖物内容,这里使用的是原生dom，使用class，不使用className
    label.setContent(`
      <div class="${styles.bubble}">
        <p class="${styles.name}">${areaName}</p>
        <p>${count}套</p>
      </div>
    `)

    // 调用 setStyle 方法设置样式
    label.setStyle(labelStyle)

    // 给房源覆盖物添加单击事件
    label.addEventListener('click', () => {
      // 获取到唯一标识 label.id
      // console.log('click了##########', label.id)
      // 调用 renderOverlays方法，获取该区域下的房源数据
      renderOverlays(label.id)
      // 放大地图，以当前点击的覆盖物为中心放大地图。第一个参数：当前坐标对象。第二个参数：放大级别
      React.map.centerAndZoom(areaPoint, zoom)
      // 调用 clearOverlays() 方法清除当前覆盖物信息。
      React.map.clearOverlays()
    })

    // 在React.map对象上调用 addOverlay 方法，将覆盖物添加到地图中
    React.map.addOverlay(label)
  }

  // createRect：根据传入的数据创建小区的覆盖物，绑定事件（移动地图、渲染房源列表）
  const createRect = (areaPoint, areaName, value, count) => {
    console.log('进入小区')
    // 创建覆盖物
    const opts = {
      position: areaPoint, // 指定标注所在的地理位置
      offset: new BMapGL.Size(-50, -28), // 设置偏移量
    }
    // 创建Label实例对象,标注对象，设置 setContent 后，第一个参数中设置的文本内容就失效了，因此直接清空即可。
    const label = new BMapGL.Label('', opts)

    // 给每一个覆盖物添加唯一标识
    label.id = value

    // 设置房源覆盖物内容,这里使用的是原生dom，使用class，不使用className
    label.setContent(`
      <div class="${styles.rect}">
        <p class="${styles.housename}">${areaName}</p>
        <p class="${styles.housenum}">${count}套</p>
        <i class="${styles.arrow}"></i>
      </div>
    `)

    // 调用 setStyle 方法设置样式
    label.setStyle(labelStyle)

    // 给房源覆盖物添加单击事件
    label.addEventListener('click', (e) => {
      // console.log(e)
      // 调用获取小区数据的方法,把当前id值传递过去
      getHousesList(value)
      // 拿到当前坐标的位置
      const target = e.domEvent.changedTouches[0]
      // 调用地图的panBy()方法，移动地图到中间位置
      React.map.panBy(
        window.innerWidth / 2 - target.clientX,
        (window.innerHeight - 330) / 2 - target.clientY
      )
    })

    // 在React.map对象上调用 addOverlay 方法，将覆盖物添加到地图中
    React.map.addOverlay(label)
  }

  // 获取该小区的房源数据
  const getHousesList = async (id) => {
    const { data: res } = await getHousesListAPI(id)
    console.log('房屋列表', res.body.list)
    setHouseList(res.body.list)
    setIsHouseList(true) // 展示房源列表
  }

  return (
    <div className="map">
      {/* 顶部导航组件 */}
      <NavHeader title="地图找房"></NavHeader>
      {/* 2.地图容器元素 */}
      <div id="container"></div>

      {/* 小区房源列表 */}
      {/* 添加 styles.show 展示房屋列表 */}
      {isHouseList ? (
        <div className={styles.cityCon}>
          <div
            className={[
              styles.houseList,
              houseList.length ? styles.show : '',
            ].join('')}
          >
            <div className={styles.titleWrap}>
              {/* 标题 */}
              <h1 className={styles.listTitle}>房屋列表</h1>
              <Link className={styles.titleMore} to="/houseList">
                更多房源
              </Link>
            </div>

            {houseList.map((item) => (
              <div
                className={styles.houseItems}
                key={item.houseCode}
                onClick={() => navigate(`/detail?id=${item.houseCode}`)}
              >
                {/* 房屋结构 */}
                <div className={styles.house}>
                  <div className={styles.imgWrap}>
                    <img
                      className={styles.img}
                      src={serverurl + item.houseImg}
                      alt=""
                    />
                  </div>
                  <div className={styles.content}>
                    <h3 className={styles.title}>{item.title}</h3>
                    <div className={styles.desc}>{item.desc}</div>
                    <div className={styles.tags}>
                      {/* 渲染标签 */}
                      {item.tags.map((tag, index) => {
                        const classTag = 'tag' + (index + 1)
                        return (
                          <span
                            className={[styles[classTag]].join('')}
                            key={tag}
                          >
                            {tag}
                          </span>
                        )
                      })}
                    </div>
                    <div className={styles.price}>
                      <span className={styles.priceNum}>{item.price}</span>{' '}
                      元/月
                    </div>
                  </div>
                </div>
              </div>
            ))}
          </div>
        </div>
      ) : (
        ''
      )}
    </div>
  )
}

export default Map

// 功能分析：
// 1. 获取房源数据，渲染覆盖物
// 2. 点击覆盖物后：1放大地图，2获取数据，渲染下一级覆盖物（重复第一步）
// 3. 区、镇：单击事件中，清除现有覆盖物，创建新的覆盖物。
// 4. 小区：不清楚覆盖物。移动地图，展示该小区下面的房源列表。

// 渲染所有区房源覆盖物
// 1. 获取房源数据
// 2. 遍历数据，创建覆盖物，给每一个覆盖物添加唯一标识（后面要用）
// 3. 在单击事件中，获取到当前单机项的唯一标识
// 4. 放大地图(级别为13),调用clearOverlays()方法清除当前覆盖物

// 封装流程
// 1. renderOverlays()作为入口：(1)：接收区域id作为参数，获取该区域下的房源数据。(2)：获取覆盖物类型以及下级地图缩放级别
// 2. createOverlays()方法：根据传入的类型，调用对应的方法，创建覆盖物
// 3. createCircle()方法：根据传入的数据创建区、镇的覆盖物，绑定事件（放大地图、清除覆盖物、渲染下一级房源数据）
// 4. createRect()方法：根据传入的数据创建小区的覆盖物，绑定事件（移动地图、渲染房源列表）
// 5. getTypeAndZoom()方法：计算类型和缩放级别

// createRect方法业务
// 1. 创建Label、设置样式、设置HTML内容、绑定单击事件
// 2. 再单击事件中，获取该小区的房源数据
// 3. 展示房源列表
// 4. 渲染获取到的房源数据
// 5. 调用地图的 panBy() 方法，移动地图到中间位置
// 6. 监听地图的 movestart 事件，在地图移动时隐藏房源列表
